import scrapy
from forex_spider.items import ForexItem
from lxml import etree
import re
from datetime import datetime

class BocForexSpider(scrapy.Spider):
    """
    招商银行外汇牌价爬虫
    爬取地址: https://www.boc.cn/sourcedb/whpj/
    """
    name = 'boc_forex'
    allowed_domains = ['boc.cn']
    start_urls = ['https://www.boc.cn/sourcedb/whpj/']
    
    # 货币代码映射表（用于标准化货币名称）
    CURRENCY_MAPPING = {
        '美元': 'USD',
        '欧元': 'EUR', 
        '英镑': 'GBP',
        '日元': 'JPY',
        '港币': 'HKD',
        '加拿大元': 'CAD',
        '澳大利亚元': 'AUD',
        '新加坡元': 'SGD',
        '瑞士法郎': 'CHF',
        '瑞典克朗': 'SEK',
        '挪威克朗': 'NOK',
        '丹麦克朗': 'DKK',
        '澳门元': 'MOP',
        '新西兰元': 'NZD',
        '韩元': 'KRW',
        '泰铢': 'THB',
        '菲律宾比索': 'PHP',
        '俄罗斯卢布': 'RUB',
        '新台币': 'TWD',
        '阿联酋迪拉姆': 'AED',
        '巴西里亚尔': 'BRL',
        '印尼卢比': 'IDR',
        '印度卢比': 'INR',
        '南非兰特': 'ZAR',
        '沙特里亚尔': 'SAR',
        '土耳其里拉': 'TRY',
        '马来西亚林吉特': 'MYR'
    }

    def parse(self, response):
        """
        解析外汇牌价页面
        """
        try:
            self.logger.info(f"开始解析外汇数据，URL: {response.url}")
            
            # 使用XPath提取表格数据
            # 外汇数据通常在class为"publish"的div下面的table中
            tables = response.xpath('//div[@class="publish"]//table')
            
            if not tables:
                self.logger.warning("未找到外汇数据表格")
                # 尝试其他可能的表格选择器
                tables = response.xpath('//table[contains(@class, "table")]')
            
            for table_index, table in enumerate(tables):
                self.logger.info(f"正在解析第{table_index + 1}个表格")
                
                # 提取表格行（跳过表头）
                rows = table.xpath('.//tr[position()>1]')
                
                for row_index, row in enumerate(rows):
                    try:
                        # 提取单元格数据
                        cells = row.xpath('./td//text()').getall()
                        
                        if len(cells) >= 7:  # 确保有足够的数据列
                            item = self.parse_forex_row(cells, row_index + 1)
                            if item:
                                yield item
                                
                    except Exception as e:
                        self.logger.error(f"解析第{row_index + 1}行数据时出错: {e}")
                        continue
                        
        except Exception as e:
            self.logger.error(f"解析页面时发生错误: {e}")

    def parse_forex_row(self, cells, row_number):
        """
        解析外汇数据行
        """
        try:
            # 清理数据：去除空白字符
            cleaned_cells = [cell.strip() for cell in cells if cell.strip()]
            
            if len(cleaned_cells) < 7:
                return None
                
            item = ForexItem()
            
            # 解析货币名称（第一列）
            currency_name = cleaned_cells[0]
            item['currency'] = self.standardize_currency_name(currency_name)
            
            # 解析价格数据
            # 现汇买入价（第二列）
            item['tbp'] = self.parse_price(cleaned_cells[1])
            # 现钞买入价（第三列）
            item['cbp'] = self.parse_price(cleaned_cells[2])
            # 现汇卖出价（第四列）
            item['tsp'] = self.parse_price(cleaned_cells[3])
            # 现钞卖出价（第五列）
            item['csp'] = self.parse_price(cleaned_cells[4])
            
            # 解析发布时间（最后一列）
            publish_time = cleaned_cells[-1]
            item['publish_time'] = self.standardize_time(publish_time)
            
            self.logger.debug(f"成功解析第{row_number}行数据: {item['currency']}")
            return item
            
        except Exception as e:
            self.logger.error(f"解析第{row_number}行数据失败: {e}")
            return None

    def parse_price(self, price_str):
        """
        解析价格字符串，转换为浮点数
        """
        try:
            # 移除可能存在的逗号等分隔符
            cleaned = re.sub(r'[^\d.]', '', price_str)
            return float(cleaned) if cleaned else 0.0
        except (ValueError, TypeError):
            return 0.0

    def standardize_currency_name(self, currency_name):
        """
        标准化货币名称
        """
        # 如果货币名称在映射表中，返回标准名称
        if currency_name in self.CURRENCY_MAPPING:
            return f"{currency_name}({self.CURRENCY_MAPPING[currency_name]})"
        return currency_name

    def standardize_time(self, time_str):
        """
        标准化时间格式
        """
        try:
            # 尝试解析各种时间格式
            time_formats = [
                '%Y.%m.%d %H:%M:%S',
                '%Y-%m-%d %H:%M:%S',
                '%Y/%m/%d %H:%M:%S',
                '%H:%M:%S'
            ]
            
            for fmt in time_formats:
                try:
                    dt = datetime.strptime(time_str, fmt)
                    return dt.strftime('%Y-%m-%d %H:%M:%S')
                except ValueError:
                    continue
                    
            # 如果无法解析，返回原始字符串
            return time_str
            
        except Exception:
            return time_str